package post

import (
	"context"
	"strconv"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/utils/pointy"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/forum/model"
	"mall/service/forum/rpc/internal/svc"
	"mall/service/forum/rpc/internal/utils"
	"mall/service/forum/rpc/internal/utils/errorhandler"
	"mall/service/forum/rpc/types/forum"

	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetPostByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetPostByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetPostByIdLogic {
	return &BackendGetPostByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetPostByIdLogic) BackendGetPostById(in *forum.PostIdReq) (*forum.ForumPostInfo, error) {
	if in.Id == 0 {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	res, err := l.svcCtx.Post.FindOne(l.ctx, in.Id)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	var meta []*forum.MetaInfo
	if in.WithMeta != nil && *in.WithMeta > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.ForumPostMetumColumns.PostID] = map[string][]any{
			"equalTo": {in.Id},
		}
		list, _, err := l.svcCtx.Post.GetMeta(l.ctx, model.M{}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				if len(v.MetaKey) > 0 && (v.MetaKey == "_thumbnail_id" || v.MetaKey == "_thumbnail_url") {
					continue
				}

				if len(v.MetaKey) > 0 && v.MetaValue.Valid {
					key := v.MetaKey
					val := v.MetaValue.String
					switch key {
					case "_photo_count":
						meta = append(meta, &forum.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer("photoCount"),
							Value: pointy.GetPointer(val),
						})
					case "_view_count":
						meta = append(meta, &forum.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer("viewCount"),
							Value: pointy.GetPointer(val),
						})
					case "_comment_count":
						meta = append(meta, &forum.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer("commentCount"),
							Value: pointy.GetPointer(val),
						})
					case "_forward_count":
						meta = append(meta, &forum.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer("forwardCount"),
							Value: pointy.GetPointer(val),
						})
					case "_upvote_count", "title_extra", "keywords_extra", "description_extra":
						//
					default:
						meta = append(meta, &forum.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer(key),
							Value: pointy.GetPointer(val),
						})
					}
				}
			}
		}
	}

	var media []*forum.MediaInfo
	if in.WithMedia != nil && *in.WithMedia > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.ForumAttachmentRelationshipColumns.ObjectID] = map[string][]any{
			"equalTo": {in.Id},
		}
		filterMap[model.ForumAttachmentRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": {globalkey.AttachmentLogTypeForumPost},
		}
		var orderBy string = model.ForumAttachmentRelationshipColumns.AttachmentThumbnail + " DESC, " +
			model.ForumAttachmentRelationshipColumns.AttachmentOrder
		list, _, err := l.svcCtx.Post.GetMedia(l.ctx, model.M{
			"orderBy": orderBy,
		}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				media = append(media, &forum.MediaInfo{
					Uid:       &v.AttachmentRelationshipID,
					Id:        pointy.GetPointer(strconv.FormatInt(int64(v.AttachmentID), 10)),
					Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
					Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
					Uri:       &v.AttachmentSource,
					Url:       &v.AttachmentImageURL,
					AltText:   &v.AttachmentImageAlt,
					MetaData:  &v.AttachmentImageMeta,
				})
			}
		}
	}

	var cards []*forum.PostCardInfo
	if in.WithCard != nil && *in.WithCard > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.ForumPostCardColumns.PostID] = map[string][]any{
			"equalTo": {in.Id},
		}
		list, _, err := l.svcCtx.Post.GetCard(l.ctx, model.M{}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				var objectType string = utils.FormatCardType(int32(v.ObjectType))
				cards = append(cards, &forum.PostCardInfo{
					Uid:      &v.ID,
					Id:       &v.ObjectID,
					Type:     pointy.GetPointer(objectType),
					LinkUrl:  &v.LinkURL,
					Title:    &v.Title,
					PicUrl:   &v.PicURL,
					Subtitle: &v.Subtitle,
					Label:    &v.Label,
					Price:    &v.Price,
				})
			}
		}
	}

	var tags []*forum.TermInfo
	if in.WithTag != nil && *in.WithTag > 0 {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.ForumTermRelationshipColumns.ObjectID] = map[string][]any{
			"equalTo": {in.Id},
		}
		subFilterMap[model.ForumTermRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": {globalkey.AttachmentLogTypeForumPost},
		}
		list, _, err := l.svcCtx.ForumTerm.GetRelationshipList(l.ctx, model.M{
			"select": model.ForumTermRelationshipColumns.ObjectID + "," + model.ForumTermRelationshipColumns.TermID,
		}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			var tids []any
			for _, v := range list {
				tids = append(tids, v.TermID)
			}

			termFilterMap := make(map[string]map[string][]any)
			termFilterMap[model.ForumTermColumns.TermID] = map[string][]any{
				"in": tids,
			}
			terms, _, err := l.svcCtx.ForumTerm.GetList(l.ctx, model.M{}, -1, termFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(terms) > 0 {
				for _, term := range terms {
					tags = append(tags, &forum.TermInfo{
						Id:   &term.TermID,
						Name: &term.Name,
						Slug: &term.Slug,
					})
				}
			}
		}
	}

	return &forum.ForumPostInfo{
		Id:                  &res.PostID,
		PostTitle:           &res.PostTitle,
		PostContent:         &res.PostContent,
		PostContentFiltered: &res.PostContentFiltered,
		PostExcerpt:         &res.PostExcerpt,
		ForumId:             &res.ForumID,
		TopicId:             &res.TopicID,
		ParentId:            &res.ParentID,
		AuthorId:            &res.PostAuthorID,
		Status:              pointy.GetPointer(uint32(res.PostStatus)),
		CommentStatus:       pointy.GetPointer(uint32(res.CommentStatus)),
		Sort:                pointy.GetPointer(uint32(res.Sort)),
		Sticky:              pointy.GetPointer(uint32(res.Sticky)),
		CreatedAt:           pointy.GetPointer(modelx.FormatTime(res.PostDate, "")),
		UpdatedAt:           pointy.GetPointer(modelx.FormatTime(res.PostModifiedDate, "")),
		DeletedAt:           pointy.GetPointer(modelx.FormatNullDotTime(res.DeletedAt, "")),
		AuthorAvatar:        &res.PostAuthorAvatar,
		AuthorNickname:      &res.PostAuthorNickname,
		AuthorIP:            &res.PostAuthorIP,
		AuthorRankId:        pointy.GetPointer(uint32(res.PostAuthorRankID)),
		AuthorRoleId:        pointy.GetPointer(uint32(res.PostAuthorRoleID)),
		PhotoCount:          pointy.GetPointer(uint32(res.PhotoCount)),
		Meta:                meta,
		Media:               media,
		Cards:               cards,
		Tags:                tags,
	}, nil
}
